"""
视频分析 API 路由
"""
from fastapi import APIRouter, File, UploadFile, HTTPException, BackgroundTasks, Query
from fastapi.responses import JSONResponse
from typing import Optional, List
import os
import uuid
import shutil
import mimetypes
from datetime import datetime
import logging

from app.core.config import settings
from app.models.video import (
    VideoUploadResponse, 
    VideoAnalysisRequest, 
    VideoAnalysisResponse,
    VideoAnalysisListResponse,
    DirectVideoAnalysisRequest,
    PredictionRequest,
    PredictionResponse,
    ErrorResponse,
    HealthCheckResponse,
    VideoAnalysisStatus
)
from app.services.video_analysis import video_service

logger = logging.getLogger(__name__)

router = APIRouter(prefix="/video", tags=["视频分析"])

@router.post("/upload", response_model=VideoUploadResponse, summary="上传视频文件")
async def upload_video(file: UploadFile = File(...)):
    """
    上传视频文件
    
    - 支持的格式: MP4, AVI, MOV, MKV, WMV, FLV
    - 最大文件大小: 100MB
    """
    try:
        # 检查文件类型
        file_extension = os.path.splitext(file.filename)[1].lower()
        if file_extension not in settings.ALLOWED_VIDEO_EXTENSIONS:
            raise HTTPException(
                status_code=400,
                detail=f"不支持的文件格式。支持的格式: {', '.join(settings.ALLOWED_VIDEO_EXTENSIONS)}"
            )
        
        # 检查文件大小
        file_content = await file.read()
        file_size = len(file_content)
        
        if file_size > settings.MAX_FILE_SIZE:
            raise HTTPException(
                status_code=400,
                detail=f"文件大小超过限制。最大允许大小: {settings.MAX_FILE_SIZE // (1024*1024)}MB"
            )
        
        if file_size == 0:
            raise HTTPException(status_code=400, detail="上传的文件为空")
        
        # 生成唯一文件ID和保存路径
        file_id = str(uuid.uuid4())
        safe_filename = f"{file_id}{file_extension}"
        file_path = os.path.join(settings.UPLOAD_DIR, safe_filename)
        
        # 保存文件
        with open(file_path, "wb") as buffer:
            buffer.write(file_content)
        
        logger.info(f"文件上传成功: {file.filename} -> {file_path}")
        
        return VideoUploadResponse(
            file_id=file_id,
            filename=file.filename,
            file_path=file_path,
            file_size=file_size
        )
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"文件上传失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"文件上传失败: {str(e)}")

@router.post("/analyze", response_model=VideoAnalysisResponse, summary="分析视频内容")
async def analyze_video(
    background_tasks: BackgroundTasks,
    request: VideoAnalysisRequest,
    use_keyframe_reconstruction: bool = Query(False, description="是否使用关键帧重构方法")
):
    """
    分析视频内容 - 需要先上传文件获取file_id
    
    - 支持两种方法：传统方法和关键帧重构方法
    - 传统方法：直接从原视频提取关键帧进行分析
    - 关键帧重构方法：提取关键帧->拼接为1fps视频->按30帧切割->分析每个片段
    - 返回分析任务ID，可通过ID查询结果
    """
    try:
        # 检查文件是否存在
        file_pattern = f"{request.file_id}.*"
        matching_files = [
            f for f in os.listdir(settings.UPLOAD_DIR)
            if f.startswith(request.file_id)
        ]
        
        if not matching_files:
            raise HTTPException(status_code=404, detail="视频文件不存在")
        
        video_path = os.path.join(settings.UPLOAD_DIR, matching_files[0])
        
        if not os.path.exists(video_path):
            raise HTTPException(status_code=404, detail="视频文件不存在")
        
        logger.info(f"开始分析视频: {video_path}")
        logger.info(f"使用方法: {'关键帧重构' if use_keyframe_reconstruction else '传统'}")
        
        # 执行视频分析 - 支持选择分析方法
        result = await video_service.analyze_video(
            video_path=video_path,
            prompt=request.prompt,
            max_frames=request.max_frames,
            max_tokens=request.max_tokens,
            scene_threshold=request.scene_threshold,
            use_keyframe_reconstruction=use_keyframe_reconstruction
        )
        
        return VideoAnalysisResponse(
            analysis_id=result["analysis_id"],
            file_id=request.file_id,
            status=result["status"],
            result=result["result"],
            ollama_summary=result.get("ollama_summary", {}).get("summary") if result.get("ollama_summary") else None,
            error_message=result["error_message"],
            created_at=result.get("completed_at", datetime.now()),
            completed_at=result.get("completed_at"),
            processing_time=result.get("processing_time")
        )
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"视频分析失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"视频分析失败: {str(e)}")

@router.post("/analyze-direct", response_model=PredictionResponse, summary="直接分析视频内容（推荐）")
async def analyze_video_direct(request: DirectVideoAnalysisRequest):
    """
    直接分析视频内容 - 支持URL和本地文件路径（推荐使用此API）
    
    - **video**: 视频URL或本地文件路径
    - **prompt**: 分析提示词
    - **scene_threshold**: 场景检测阈值
    - **max_tokens**: 最大生成token数
    - **use_keyframe_reconstruction**: 是否使用关键帧重构方法
    
    支持格式:
    - URL: http://example.com/video.mp4
    - 本地路径: /path/to/video.mp4 或 \\\\server\\path\\video.mp4
    
    两种分析方法：
    - 传统方法(false): 直接提取关键帧分析，速度快
    - 关键帧重构(true): 提取关键帧->拼接视频->切割->逐段分析，更全面
    """
    try:
        logger.info(f"收到直接分析请求 - Video: {request.video[:100]}...")
        logger.info(f"Prompt: {request.prompt}")
        logger.info(f"使用关键帧重构: {request.use_keyframe_reconstruction}")
        logger.info(f"使用直接场景切分: {request.use_direct_split}")
        logger.info(f"场景阈值: {request.scene_threshold}")
        logger.info(f"最大tokens: {request.max_tokens}")
        
        # 调用分析服务
        result = await video_service.analyze_video(
            video_path=request.video,
            prompt=request.prompt,
            max_tokens=request.max_tokens,
            scene_threshold=request.scene_threshold,
            custom_summary_prompt=request.custom_summary_prompt,
            use_keyframe_reconstruction=request.use_keyframe_reconstruction,
            use_direct_split=request.use_direct_split  # 传递新参数
        )
        
        return PredictionResponse(
            output=result["result"] or "分析失败",
            processing_time=result.get("processing_time", 0),
            frames_processed=result.get("metadata", {}).get("keyframes_extracted", 0) if request.use_keyframe_reconstruction else result.get("metadata", {}).get("frames_processed", 0),
            batch_count=result.get("metadata", {}).get("segments_created", 1) if request.use_keyframe_reconstruction else result.get("metadata", {}).get("batch_count", 1),
            frame_extraction_method=result.get("metadata", {}).get("method", "keyframe_reconstruction" if request.use_keyframe_reconstruction else "traditional"),
            ollama_summary=result.get("ollama_summary"),
            ollama_enabled=result.get("metadata", {}).get("ollama_enabled", False),
            ollama_model=result.get("metadata", {}).get("ollama_model")
        )
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"视频分析失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"视频分析失败: {str(e)}")

@router.post("/analyze-keyframe", response_model=VideoAnalysisResponse, summary="关键帧重构分析视频内容")
async def analyze_video_keyframe_reconstruction(
    background_tasks: BackgroundTasks,
    request: VideoAnalysisRequest,
    fps_for_keyframe_video: int = Query(1, description="关键帧视频的帧率（秒/帧）"),
    max_frames_per_segment: int = Query(30, description="每个片段最大帧数")
):
    """
    使用关键帧重构方法分析视频内容
    
    流程：
    1. 提取关键帧
    2. 拼接成指定帧率的视频 (默认1fps)
    3. 按指定帧数切割成多个片段 (默认30帧/片段)
    4. 用SmolVLM2分析每个片段
    5. 合并分析结果
    6. 用Ollama生成总结
    """
    try:
        # 检查文件是否存在
        file_pattern = f"{request.file_id}.*"
        matching_files = [
            f for f in os.listdir(settings.UPLOAD_DIR)
            if f.startswith(request.file_id)
        ]
        
        if not matching_files:
            raise HTTPException(status_code=404, detail="视频文件不存在")
        
        video_path = os.path.join(settings.UPLOAD_DIR, matching_files[0])
        
        if not os.path.exists(video_path):
            raise HTTPException(status_code=404, detail="视频文件不存在")
        
        logger.info(f"开始关键帧重构分析: {video_path}")
        logger.info(f"关键帧视频FPS: {fps_for_keyframe_video}, 每段最大帧数: {max_frames_per_segment}")
        
        # 执行关键帧重构分析
        result = await video_service.analyze_video_with_keyframe_reconstruction(
            video_path_or_url=video_path,
            prompt=request.prompt,
            scene_threshold=request.scene_threshold,
            max_tokens=request.max_tokens,
            fps_for_keyframe_video=fps_for_keyframe_video,
            max_frames_per_segment=max_frames_per_segment
        )
        
        return VideoAnalysisResponse(
            analysis_id=result["analysis_id"],
            file_id=request.file_id,
            status=result["status"],
            result=result["result"],
            ollama_summary=result.get("ollama_summary", {}).get("summary") if result.get("ollama_summary") else None,
            error_message=result["error_message"],
            created_at=result.get("completed_at", datetime.now()),
            completed_at=result.get("completed_at"),
            processing_time=result.get("processing_time")
        )
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"关键帧重构分析失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"关键帧重构分析失败: {str(e)}")

@router.get("/analysis/{analysis_id}", response_model=VideoAnalysisResponse, summary="获取分析结果")
async def get_analysis_result(analysis_id: str):
    """
    根据分析ID获取分析结果
    """
    try:
        result = video_service.get_analysis_result(analysis_id)
        
        if not result:
            raise HTTPException(status_code=404, detail="分析结果不存在")
        
        return VideoAnalysisResponse(
            analysis_id=result["analysis_id"],
            file_id="",  # 从缓存中可能没有这个信息
            status=result["status"],
            result=result["result"],
            error_message=result["error_message"],
            created_at=result.get("completed_at", datetime.now()),
            completed_at=result.get("completed_at"),
            processing_time=result.get("processing_time")
        )
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"获取分析结果失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"获取分析结果失败: {str(e)}")

@router.get("/analyses", response_model=VideoAnalysisListResponse, summary="获取分析历史")
async def get_analyses(
    page: int = Query(1, ge=1, description="页码"),
    page_size: int = Query(10, ge=1, le=100, description="每页大小")
):
    """
    获取所有分析结果的分页列表
    """
    try:
        all_analyses = video_service.get_all_analyses()
        
        # 按完成时间倒序排序
        all_analyses.sort(
            key=lambda x: x.get("completed_at", datetime.min),
            reverse=True
        )
        
        # 分页
        start_idx = (page - 1) * page_size
        end_idx = start_idx + page_size
        page_analyses = all_analyses[start_idx:end_idx]
        
        # 转换为响应模型
        items = []
        for analysis in page_analyses:
            items.append(VideoAnalysisResponse(
                analysis_id=analysis["analysis_id"],
                file_id="",  # 从缓存中可能没有这个信息
                status=analysis["status"],
                result=analysis["result"],
                error_message=analysis["error_message"],
                created_at=analysis.get("completed_at", datetime.now()),
                completed_at=analysis.get("completed_at"),
                processing_time=analysis.get("processing_time")
            ))
        
        return VideoAnalysisListResponse(
            total=len(all_analyses),
            page=page,
            page_size=page_size,
            items=items
        )
        
    except Exception as e:
        logger.error(f"获取分析历史失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"获取分析历史失败: {str(e)}")

@router.post("/summarize", summary="使用Ollama总结视频分析结果")
async def summarize_analysis(
    analysis_id: str,
    custom_prompt: Optional[str] = None
):
    """
    使用Ollama本地LLM对已有的视频分析结果进行总结
    
    - analysis_id: 已完成的分析结果ID
    - custom_prompt: 自定义总结提示词（可选）
    """
    try:
        # 获取原始分析结果
        original_result = video_service.get_analysis_result(analysis_id)
        if not original_result:
            raise HTTPException(status_code=404, detail="分析结果不存在")
        
        if original_result["status"] != VideoAnalysisStatus.COMPLETED:
            raise HTTPException(status_code=400, detail="分析尚未完成，无法进行总结")
        
        if not original_result.get("result"):
            raise HTTPException(status_code=400, detail="分析结果为空，无法进行总结")
        
        logger.info(f"开始为分析ID {analysis_id} 生成Ollama总结")
        
        # 清理GPU内存
        video_service.cleanup_gpu_memory()
        
        # 调用Ollama总结
        summary_result = await video_service.summarize_with_ollama(
            video_analysis_result=original_result["result"],
            custom_prompt=custom_prompt
        )
        
        # 更新原始结果，添加总结
        original_result["ollama_summary"] = summary_result
        original_result["metadata"]["ollama_enabled"] = True
        original_result["metadata"]["ollama_model"] = video_service.ollama_model
        
        # 更新缓存
        video_service._analysis_cache[analysis_id] = original_result
        
        return {
            "analysis_id": analysis_id,
            "summary": summary_result["summary"],
            "summary_status": summary_result["status"],
            "processing_time": summary_result["processing_time"],
            "model_used": summary_result["model_used"],
            "error": summary_result.get("error")
        }
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Ollama总结失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"Ollama总结失败: {str(e)}")

@router.delete("/analysis/{analysis_id}", summary="删除分析结果")
async def delete_analysis(analysis_id: str):
    """
    删除指定的分析结果
    """
    try:
        if analysis_id not in video_service._analysis_cache:
            raise HTTPException(status_code=404, detail="分析结果不存在")
        
        del video_service._analysis_cache[analysis_id]
        
        return {"message": "分析结果已删除", "analysis_id": analysis_id}
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"删除分析结果失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"删除分析结果失败: {str(e)}")

@router.post("/clear-cache", summary="清空分析缓存")
async def clear_analysis_cache():
    """
    清空所有分析结果缓存
    """
    try:
        video_service.clear_cache()
        return {"message": "分析缓存已清空"}
        
    except Exception as e:
        logger.error(f"清空缓存失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"清空缓存失败: {str(e)}")

@router.get("/model/info", summary="获取模型信息")
async def get_model_info():
    """
    获取当前加载的模型信息和系统状态
    """
    try:
        model_info = video_service.get_model_info()
        
        return HealthCheckResponse(
            status="healthy" if model_info["model_loaded"] else "not_ready",
            service=settings.PROJECT_NAME,
            version=settings.VERSION,
            gpu_available=model_info["cuda_available"],
            model_loaded=model_info["model_loaded"]
        )
        
    except Exception as e:
        logger.error(f"获取模型信息失败: {str(e)}")
        return HealthCheckResponse(
            status="error",
            service=settings.PROJECT_NAME,
            version=settings.VERSION,
            gpu_available=False,
            model_loaded=False
        )

@router.post("/model/initialize", summary="初始化模型")
async def initialize_model():
    """
    手动初始化视频分析模型
    """
    try:
        success = await video_service.initialize_model()
        
        if success:
            return {"message": "模型初始化成功", "status": "ready"}
        else:
            raise HTTPException(status_code=500, detail="模型初始化失败")
            
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"模型初始化失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"模型初始化失败: {str(e)}")

@router.post("/model/reinitialize", summary="强制重新初始化模型")
async def force_reinitialize_model():
    """
    强制重新初始化模型
    用于模型出错或需要重新加载的情况
    """
    try:
        logger.info("收到强制重新初始化请求")
        success = await video_service.force_reinitialize_model()
        
        if success:
            return {"message": "模型重新初始化成功", "status": "ready"}
        else:
            raise HTTPException(status_code=500, detail="模型重新初始化失败")
            
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"模型重新初始化失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"模型重新初始化失败: {str(e)}")

@router.get("/model/status", summary="获取模型详细状态")
async def get_model_status():
    """
    获取模型的详细状态信息，包括初始化状态
    """
    try:
        status_info = video_service.get_initialization_status()
        model_info = video_service.get_model_info()
        
        return {
            "ready": video_service.is_model_ready(),
            "detailed_status": status_info,
            "model_info": model_info,
            "recommendations": _get_status_recommendations(status_info)
        }
        
    except Exception as e:
        logger.error(f"获取模型状态失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"获取模型状态失败: {str(e)}")

def _get_status_recommendations(status: dict) -> list:
    """根据状态提供建议"""
    recommendations = []
    
    if not status.get("ready"):
        if not status.get("model_loaded"):
            recommendations.append("模型未加载，请调用 /model/initialize 初始化模型")
        elif status.get("currently_initializing"):
            recommendations.append("模型正在初始化中，请稍等")
        elif not status.get("model_exists") or not status.get("processor_exists"):
            recommendations.append("模型组件缺失，请调用 /model/reinitialize 重新初始化")
        else:
            recommendations.append("模型状态异常，建议重新初始化")
    else:
        recommendations.append("模型已准备就绪，可以进行视频分析")
    
    return recommendations

@router.post("/predictions", response_model=PredictionResponse, summary="预测视频内容")
async def predict_video(request: PredictionRequest):
    """
    预测视频内容 - 支持URL和本地文件路径
    
    - **video**: 视频URL或本地文件路径
    - **prompt**: 分析提示词
    - **num_frames**: 帧间隔秒数（如10=每10秒一帧，0.1=每秒10帧）
    - **max_new_tokens**: 最大生成token数
    
    支持格式:
    - URL: http://example.com/video.mp4
    - 本地路径: /path/to/video.mp4 或 D:\\videos\\sample.mp4
    
    时间间隔说明:
    - 1.0 = 每秒采样1帧
    - 0.5 = 每0.5秒采样1帧（每秒2帧）
    - 2.0 = 每2秒采样1帧
    - 10.0 = 每10秒采样1帧
    """
    try:
        logger.info(f"收到预测请求 - Video: {request.video[:100]}...")
        logger.info(f"Prompt: {request.prompt}")
        logger.info(f"Frame interval: {request.num_frames}s")
        logger.info(f"Max tokens: {request.max_new_tokens}")
        
        # 调用预测服务
        result = await video_service.predict_video(
            video_path_or_url=request.video,
            prompt=request.prompt,
            frame_interval=request.num_frames,
            max_tokens=request.max_new_tokens
        )
        
        return PredictionResponse(
            output=result["output"],
            processing_time=result["processing_time"],
            frames_processed=result["frames_processed"],
            video_duration=result["video_duration"],
            frame_interval=result["frame_interval"]
        )
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"视频预测失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"视频预测失败: {str(e)}")